﻿// ---------------------------------------------------------------------------------------------------------------------
//   Copyright (c) SRT Solutions 2009. All rights reserved.
// ---------------------------------------------------------------------------------------------------------------------

using System;
using System.Collections.Generic;
using System.Linq;

using NUnit.Framework;

using SRTSolutions.Elevate;

namespace SRTSolutions.Elevate.Guide
{
    public class DelayedLists
    {
        [Test]
        public void ConstructingADelayedList()
        {
            //given a sequence
            int count = 0;
            var sequence =
                1.Through(5)
                .Select(value => { count++; return value; });

            //we can construct a delayed list like this
            IList<int> result = sequence.ToDelayedList();

            //when we do this, none of the values have been walked
            Assert.AreEqual(0, count);

            //once we get an item, though
            Assert.AreEqual(1, result[0]);

            //the entire list gets walked.
            Assert.AreEqual(5, count);
        }

        [Test]
        public void DelayedListWithInitialCount()
        {
            //given a sequence
            int count = 0;
            var sequence =
                1.Through(5)
                .Select(value => { count++; return value; });

            //we can construct a delayed list and specify it's initial count like this
            var result = sequence.ToDelayedList(5);

            //this way, the input sequence won't be walked even when getting the count.
            Assert.AreEqual(0, count);
            Assert.AreEqual(5, result.Count);
            Assert.AreEqual(0, count);

            //after messing with values, though, the count works just like you'd expect in
            //a normal IList
            result.Add(123);
            Assert.AreEqual(5, count);
            Assert.AreEqual(6, result.Count);
        }

        #region Unit Tests

        IList<int> GetDelayedList()
        {
            return 1.Through(5).ToDelayedList();
        }

        //basic sanity checks since the implementation is dead simple for these

        [Test]
        public void DelayedListGet()
        {
            int count = 0;
            var list =
                1.Through(5)
                .Select(value => { count++; return value; })
                .ToDelayedList();

            Assert.AreEqual(1, list[0]);

            Assert.AreEqual(5, count);

            Assert.AreEqual(2, list[1]);
            Assert.AreEqual(3, list[2]);
            Assert.AreEqual(4, list[3]);
            Assert.AreEqual(5, list[4]);
        }

        [Test]
        public void DelayedListSet()
        {
            int count = 0;
            var list =
                1.Through(5)
                .Select(value => { count++; return value; })
                .ToDelayedList();


            Assert.AreEqual(3, list[2]);

            list[2] = 151;

            Assert.AreEqual(5, count);
            Assert.AreEqual(list[2], 151);
        }

        [Test]
        public void DelayedListIndexOf()
        {
            int count = 0;
            var list =
                1.Through(5)
                .Select(value => { count++; return value; })
                .ToDelayedList();

            Assert.AreEqual(4, list.IndexOf(5));
            Assert.AreEqual(5, count);
        }

        [Test]
        public void DelayedListInsert()
        {
            int count = 0;
            var list =
                1.Through(5)
                .Select(value => { count++; return value; })
                .ToDelayedList();

            list.Insert(2, 89);

            Assert.AreEqual(5, count);
            Assert.AreEqual(6, list.Count);
            Assert.AreEqual(89, list[2]);
        }

        [Test]
        public void DelayedListRemoveAt()
        {
            int count = 0;
            var list =
                1.Through(5)
                .Select(value => { count++; return value; })
                .ToDelayedList();

            list.RemoveAt(2);

            Assert.AreEqual(5, count);
            Assert.AreEqual(4, list.Count);
            Assert.AreEqual(Seq.Build(1,2,4,5), list);
        }

        [Test]
        public void DelayedListAdd()
        {
            int count = 0;
            var list =
                1.Through(5)
                .Select(value => { count++; return value; })
                .ToDelayedList();

            list.Add(123);

            Assert.AreEqual(5, count);
            Assert.AreEqual(123, list[5]);
        }

        [Test]
        public void DelayedListClear()
        {
            int count = 0;
            var list =
                1.Through(5)
                .Select(value => { count++; return value; })
                .ToDelayedList();

            list.Clear();

            Assert.AreEqual(5, count);
            Assert.AreEqual(0, list.Count);
        }

        [Test]
        public void DelayedListContains()
        {
            int count = 0;
            var list =
                1.Through(5)
                .Select(value => { count++; return value; })
                .ToDelayedList();

            Assert.IsTrue(list.Contains(2));
            Assert.AreEqual(5, count);

            Assert.IsFalse(list.Contains(-1));
            Assert.AreEqual(5, count);
        }

        [Test]
        public void DelayedListCopyTo()
        {
            int count = 0;
            var list =
                1.Through(5)
                .Select(value => { count++; return value; })
                .ToDelayedList();

            var copy = new int[10];
            list.CopyTo(copy, 4);

            Assert.AreEqual(5, count);
            Assert.AreEqual(Seq.Build(0,0,0,0,1,2,3,4,5,0), copy);
        }

        [Test]
        public void DelayedListIsReadOnly()
        {
            int count = 0;
            var list =
                1.Through(5)
                .Select(value => { count++; return value; })
                .ToDelayedList();

            Assert.IsFalse(list.IsReadOnly);
            Assert.AreEqual(0, count);
        }

        [Test]
        public void DelayedListRemove()
        {
            int count = 0;
            var list =
                1.Through(5)
                .Select(value => { count++; return value; })
                .ToDelayedList();

            list.Remove(3);

            Assert.AreEqual(5, count);
            Assert.AreEqual(Seq.Build(1,2,4,5), list);
        }

        #endregion
    }
}
